home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 53 / PC Actual CD 53.iso / Share / Progra / python / BeOpen-Python-2.0.exe / COLORDELEGATOR.PY < prev    next >
Encoding:
Python Source  |  2000-09-28  |  8.3 KB  |  235 lines

  1. import time
  2. import string
  3. import re
  4. import keyword
  5. from Tkinter import *
  6. from Delegator import Delegator
  7. from IdleConf import idleconf
  8.  
  9. #$ event <<toggle-auto-coloring>>
  10. #$ win <Control-slash>
  11. #$ unix <Control-slash>
  12.  
  13. __debug__ = 0
  14.  
  15.  
  16. def any(name, list):
  17.     return "(?P<%s>" % name + string.join(list, "|") + ")"
  18.  
  19. def make_pat():
  20.     kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
  21.     comment = any("COMMENT", [r"#[^\n]*"])
  22.     sqstring = r"(\b[rR])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
  23.     dqstring = r'(\b[rR])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
  24.     sq3string = r"(\b[rR])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
  25.     dq3string = r'(\b[rR])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
  26.     string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
  27.     return kw + "|" + comment + "|" + string + "|" + any("SYNC", [r"\n"])
  28.  
  29. prog = re.compile(make_pat(), re.S)
  30. idprog = re.compile(r"\s+(\w+)", re.S)
  31.  
  32. class ColorDelegator(Delegator):
  33.  
  34.     def __init__(self):
  35.         Delegator.__init__(self)
  36.         self.prog = prog
  37.         self.idprog = idprog
  38.  
  39.     def setdelegate(self, delegate):
  40.         if self.delegate is not None:
  41.             self.unbind("<<toggle-auto-coloring>>")
  42.         Delegator.setdelegate(self, delegate)
  43.         if delegate is not None:
  44.             self.config_colors()
  45.             self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
  46.             self.notify_range("1.0", "end")
  47.  
  48.     def config_colors(self):
  49.         for tag, cnf in self.tagdefs.items():
  50.             if cnf:
  51.                 apply(self.tag_configure, (tag,), cnf)
  52.         self.tag_raise('sel')
  53.  
  54.     cconf = idleconf.getsection('Colors')
  55.  
  56.     tagdefs = {
  57.         "COMMENT": cconf.getcolor("comment"),
  58.         "KEYWORD": cconf.getcolor("keyword"),
  59.         "STRING": cconf.getcolor("string"),
  60.         "DEFINITION": cconf.getcolor("definition"),
  61.         "SYNC": cconf.getcolor("sync"),
  62.         "TODO": cconf.getcolor("todo"),
  63.         "BREAK": cconf.getcolor("break"),
  64.         # The following is used by ReplaceDialog:
  65.         "hit": cconf.getcolor("hit"),
  66.         }
  67.  
  68.     def insert(self, index, chars, tags=None):
  69.         index = self.index(index)
  70.         self.delegate.insert(index, chars, tags)
  71.         self.notify_range(index, index + "+%dc" % len(chars))
  72.  
  73.     def delete(self, index1, index2=None):
  74.         index1 = self.index(index1)
  75.         self.delegate.delete(index1, index2)
  76.         self.notify_range(index1)
  77.  
  78.     after_id = None
  79.     allow_colorizing = 1
  80.     colorizing = 0
  81.  
  82.     def notify_range(self, index1, index2=None):
  83.         self.tag_add("TODO", index1, index2)
  84.         if self.after_id:
  85.             if __debug__: print "colorizing already scheduled"
  86.             return
  87.         if self.colorizing:
  88.             self.stop_colorizing = 1
  89.             if __debug__: print "stop colorizing"
  90.         if self.allow_colorizing:
  91.             if __debug__: print "schedule colorizing"
  92.             self.after_id = self.after(1, self.recolorize)
  93.  
  94.     close_when_done = None # Window to be closed when done colorizing
  95.  
  96.     def close(self, close_when_done=None):
  97.         if self.after_id:
  98.             after_id = self.after_id
  99.             self.after_id = None
  100.             if __debug__: print "cancel scheduled recolorizer"
  101.             self.after_cancel(after_id)
  102.         self.allow_colorizing = 0
  103.         self.stop_colorizing = 1
  104.         if close_when_done:
  105.             if not self.colorizing:
  106.                 close_when_done.destroy()
  107.             else:
  108.                 self.close_when_done = close_when_done
  109.  
  110.     def toggle_colorize_event(self, event):
  111.         if self.after_id:
  112.             after_id = self.after_id
  113.             self.after_id = None
  114.             if __debug__: print "cancel scheduled recolorizer"
  115.             self.after_cancel(after_id)
  116.         if self.allow_colorizing and self.colorizing:
  117.             if __debug__: print "stop colorizing"
  118.             self.stop_colorizing = 1
  119.         self.allow_colorizing = not self.allow_colorizing
  120.         if self.allow_colorizing and not self.colorizing:
  121.             self.after_id = self.after(1, self.recolorize)
  122.         if __debug__:
  123.             print "auto colorizing turned", self.allow_colorizing and "on" or "off"
  124.         return "break"
  125.  
  126.     def recolorize(self):
  127.         self.after_id = None
  128.         if not self.delegate:
  129.             if __debug__: print "no delegate"
  130.             return
  131.         if not self.allow_colorizing:
  132.             if __debug__: print "auto colorizing is off"
  133.             return
  134.         if self.colorizing:
  135.             if __debug__: print "already colorizing"
  136.             return
  137.         try:
  138.             self.stop_colorizing = 0
  139.             self.colorizing = 1
  140.             if __debug__: print "colorizing..."
  141.             t0 = time.clock()
  142.             self.recolorize_main()
  143.             t1 = time.clock()
  144.             if __debug__: print "%.3f seconds" % (t1-t0)
  145.         finally:
  146.             self.colorizing = 0
  147.         if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
  148.             if __debug__: print "reschedule colorizing"
  149.             self.after_id = self.after(1, self.recolorize)
  150.         if self.close_when_done:
  151.             top = self.close_when_done
  152.             self.close_when_done = None
  153.             top.destroy()
  154.  
  155.     def recolorize_main(self):
  156.         next = "1.0"
  157.         while 1:
  158.             item = self.tag_nextrange("TODO", next)
  159.             if not item:
  160.                 break
  161.             head, tail = item
  162.             self.tag_remove("SYNC", head, tail)
  163.             item = self.tag_prevrange("SYNC", head)
  164.             if item:
  165.                 head = item[1]
  166.             else:
  167.                 head = "1.0"
  168.  
  169.             chars = ""
  170.             next = head
  171.             lines_to_get = 1
  172.             ok = 0
  173.             while not ok:
  174.                 mark = next
  175.                 next = self.index(mark + "+%d lines linestart" %
  176.                                          lines_to_get)
  177.                 lines_to_get = min(lines_to_get * 2, 100)
  178.                 ok = "SYNC" in self.tag_names(next + "-1c")
  179.                 line = self.get(mark, next)
  180.                 ##print head, "get", mark, next, "->", `line`
  181.                 if not line:
  182.                     return
  183.                 for tag in self.tagdefs.keys():
  184.                     self.tag_remove(tag, mark, next)
  185.                 chars = chars + line
  186.                 m = self.prog.search(chars)
  187.                 while m:
  188.                     for key, value in m.groupdict().items():
  189.                         if value:
  190.                             a, b = m.span(key)
  191.                             self.tag_add(key,
  192.                                          head + "+%dc" % a,
  193.                                          head + "+%dc" % b)
  194.                             if value in ("def", "class"):
  195.                                 m1 = self.idprog.match(chars, b)
  196.                                 if m1:
  197.                                     a, b = m1.span(1)
  198.                                     self.tag_add("DEFINITION",
  199.                                                  head + "+%dc" % a,
  200.                                                  head + "+%dc" % b)
  201.                     m = self.prog.search(chars, m.end())
  202.                 if "SYNC" in self.tag_names(next + "-1c"):
  203.                     head = next
  204.                     chars = ""
  205.                 else:
  206.                     ok = 0
  207.                 if not ok:
  208.                     # We're in an inconsistent state, and the call to
  209.                     # update may tell us to stop.  It may also change
  210.                     # the correct value for "next" (since this is a
  211.                     # line.col string, not a true mark).  So leave a
  212.                     # crumb telling the next invocation to resume here
  213.                     # in case update tells us to leave.
  214.                     self.tag_add("TODO", next)
  215.                 self.update()
  216.                 if self.stop_colorizing:
  217.                     if __debug__: print "colorizing stopped"
  218.                     return
  219.  
  220.  
  221. def main():
  222.     from Percolator import Percolator
  223.     root = Tk()
  224.     root.wm_protocol("WM_DELETE_WINDOW", root.quit)
  225.     text = Text(background="white")
  226.     text.pack(expand=1, fill="both")
  227.     text.focus_set()
  228.     p = Percolator(text)
  229.     d = ColorDelegator()
  230.     p.insertfilter(d)
  231.     root.mainloop()
  232.  
  233. if __name__ == "__main__":
  234.     main()
  235.